package jef.common;

import java.io.Serializable;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;

import jef.common.annotation.ObjectName;
import jef.tools.ArrayUtils;

import com.google.common.base.Objects;

/**
 * 用List实现的最简单的Map，目标是占用内存最小，不考虑性能，事实上元素不多的情况下性能不是什么问题。
 * 
 * 这个类更多的时候是用来作为JAXB的通用Map序列化。在我修改了JAXB的实现之后，这一序列化将泛型的map作为一个单独的类型来使用.
 * 
 * 值得注意的是，为了让JAXB序列化后不显示父类AbstractMap，这里特地进行了处理，将JDK的AbstractMap拷贝了一份出来，为了加上@XmlTransient这个标签
 * 。 因此这个类没有继承JDK的AbstractMap.
 * 
 * @param <K>
 * @param <V>
 */
@ObjectName("Map")
@XmlAccessorType(XmlAccessType.FIELD)
public class SimpleMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Serializable {
	private static final long serialVersionUID = -4930667933312037159L;

	@XmlElement(nillable = false, name = "entry")
	private List<jef.common.Entry<K, V>> entries;

	public List<jef.common.Entry<K, V>> getEntries() {
		return entries;
	}

	public void setEntries(List<jef.common.Entry<K, V>> entries) {
		this.entries = entries;
	}

	public SimpleMap(jef.common.Entry<K, V>[] entries) {
		this.entries = ArrayUtils.asList(entries);
	}

	public SimpleMap() {
		this(16);
	}

	public SimpleMap(int size) {
		this.entries = new ArrayList<jef.common.Entry<K, V>>(size);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public SimpleMap(Map<K, V> map) {
		if (map instanceof SimpleMap) {
			entries = ((SimpleMap) map).entries;
		} else {
			entries = new ArrayList<jef.common.Entry<K, V>>(map.size());
			for (Entry<K, V> e : map.entrySet()) {
				entries.add(new jef.common.Entry<K, V>(e.getKey(), e.getValue()));
			}
		}
	}

	/**
	 * 在Map中添加元素，不检查重复与否
	 * 
	 * @param key
	 * @param value
	 */
	public void add(K key, V value) {
		entries.add(new jef.common.Entry<K, V>(key, value));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jef.common.AbstractMap#put(java.lang.Object, java.lang.Object)
	 */
	@Override
	public V put(K key, V value) {
		int index = -1;
		for (int i = 0; i < entries.size(); i++) {
			if (Objects.equal(entries.get(i).getKey(), key)) {
				index = i;
				break;
			}
		}
		if (index > -1) {
			entries.set(index, new jef.common.Entry<K, V>(key, value));
		} else {
			entries.add(new jef.common.Entry<K, V>(key, value));
		}
		return value;
	}

	private class EntriesIterator implements Iterator<java.util.Map.Entry<K, V>> {
		private int n = 0;

		public boolean hasNext() {
			return n < entries.size();
		}

		public java.util.Map.Entry<K, V> next() {
			java.util.Map.Entry<K, V> result = entries.get(n);
			n++;
			return result;
		}

		public void remove() {
			n--;
			entries.remove(n);
		}
	}

	public Set<java.util.Map.Entry<K, V>> entrySet() {

		return new AbstractSet<java.util.Map.Entry<K, V>>() {
			@Override
			public Iterator<java.util.Map.Entry<K, V>> iterator() {
				return new EntriesIterator();
			}

			@Override
			public int size() {
				return entries.size();
			}
		};

	}

	@Override
	public int size() {
		return entries.size();
	}

	@Override
	public void clear() {
		entries.clear();
	}

	@Override
	public Iterator<? extends java.util.Map.Entry<K, V>> entryIterator() {
		return entries.iterator();
	}

}
